#pragma once

#include <iostream>
#include <memory>
#include "sock.hpp"
#include "epoller.hpp"
#include "nocopy.hpp"
#include <string>

const int Max_Num = 1024;

class EpollServer : public NoCopy
{
public:
    EpollServer(uint16_t port = 8080)
        : _port(port)
        , _listen_sock(new Sock)
        , _epoller(new Epoller)
    {

    }

    void ServerInit()
    {
        _listen_sock->Socket();
        _listen_sock->Bind(_port);
        _listen_sock->Listen();
    }

    void Accepter()
    {
        uint16_t client_port;
        std::string client_ip;
        int sock = _listen_sock->Accept(client_ip, client_port);
        if(sock > 0)
        {
            int op = EPOLL_CTL_ADD;
            _epoller->EpollUpdate(op, sock, EPOLLIN);
        }
    
    }

    void Reader(int fd)
    {
        char buffer[1024];
        ssize_t n = read(fd, buffer, sizeof(buffer) - 1);
        if(n > 0)
        {
            buffer[n] = '\0';
            std::cout << buffer << std::endl;
            std::string out("server : ");
            out += buffer;
            write(fd, out.c_str(), out.size());
        }
        else if(n == 0)
        {
            int op = EPOLL_CTL_DEL;
            _epoller->EpollUpdate(op, fd, 0);
            close(fd);
            std::cout << "关闭文件描述符" << std::endl; 
        }
        else
        {
            int op = EPOLL_CTL_DEL;
            _epoller->EpollUpdate(op, fd, 0);
            close(fd);
            std::cout << "读取出错" << std::endl; 

        }
    }

    void Handler(struct epoll_event* recv, int num)
    {
        for(int i = 0; i < num; i++)
        {
            int fd = recv[i].data.fd;
            int event = recv[i].events;
            if(event & EPOLLIN)
            {
                if(fd == _listen_sock->GetSockfd())
                {
                    // 处理链接
                    Accepter();
                }
                else
                {
                    Reader(fd);
                }
            }

        }
    }

    void run()
    {
        _epoller->EpollUpdate(EPOLL_CTL_ADD, _listen_sock->GetSockfd(), EPOLLIN);
        while(1)
        {
            struct epoll_event events[Max_Num];
            int n = _epoller->EpollWait(events, Max_Num);
            if(n > 0)
            {
                std::cout << "资源就绪, 处理ing" << std::endl;
                Handler(events, n);
            }
            else if(n == 0)
            {
                std::cout << "资源未就绪" << std::endl;
            }
            else
            {
                std::cout << "wait err" << std::endl;
            }
        }
    }

private:
    std::shared_ptr<Sock> _listen_sock;
    std::shared_ptr<Epoller> _epoller;
    uint16_t _port;
};